#include "Image.h"
#include <stdio.h>

Image::Image(): width(0), height(0), segment(0), data(0), originX(0), originY(0)
{
}

Image::Image(unsigned int newWidth, unsigned int newHeight): segment(0), data(0)
{
	SetDimension(newWidth, newHeight);
}

Image::~Image()
{
	Clear();
}


void Image::SetDimension(unsigned int newWidth, unsigned newHeight)
{
	unsigned int newSize = newWidth * newHeight;
	unsigned int curSize = width * height;

	if (newSize != curSize)
		ClearImage();

	width = newWidth;
	height = newHeight;

	data = new unsigned char[width * height];

	originX = originY = 0;
}

void Image::Clear()
{
	ClearImage();
	ClearSegment();
}

void Image::ClearImage()
{
	if (data)
	{
		delete[] data;
		data = 0;
	}
}

void Image::ClearSegment()
{
	if (segment)
	{
		delete segment;
		segment = 0;
	}
}

void Image::ReadFromFile(const char* filename)
{
	ReadRawFromFile(filename);
}

void Image::ReadRawFromFile(const char* filename)
{
	FILE *f = fopen(filename, "rb");

	if(f == 0)
		throw "Image: Could not read file";

	unsigned int filesize;

	fseek(f, 0, SEEK_END);
	filesize = ftell(f);
	fseek(f, 0, SEEK_SET);


	if (width * height != filesize)
		throw "Image: Invalid dimension";

	
	fread(data, sizeof(unsigned char), width*height, f);

	fclose(f);
}

void Image::WriteToFile(const char* filename)
{
	WriteRawToFile(filename);
}

void Image::WriteRawToFile(const char* filename)
{
	FILE *f = fopen(filename, "wb");

	if(f == 0)
		throw "Image: Could not write to file";

	fwrite(data, sizeof(unsigned char), width*height, f);

	fclose(f);
}

void Image::SetComponent(unsigned int x, unsigned int y, unsigned char intensity)
{
	if (x >= width || y >= height)
		throw "Image: SetComponent out of bounds";

	data[x+y*width] = intensity;
}

unsigned char Image::GetComponent(unsigned int x, unsigned int y) const
{
	if (x >= width || y >= height)
		throw "Image: GetComponent out of bounds";

	return data[x+y*width];
}

unsigned char& Image::operator()(unsigned int x, unsigned int y)
{
	if (x >= width || y >= height)
		throw "Image: GetComponent out of bounds";

	return data[x+y*width];
}



void Image::InitializeSegment(unsigned int blockWidth, unsigned int blockHeight)
{
	ClearSegment();

	segment = new Image(blockWidth, blockHeight);

	segment->originX -= blockWidth;
}

Image* Image::NextSegment()
{
	Image *result = 0;

	if (!segment)
		return 0;

	segment->originX += segment->width;
	if (segment->originX >= width)
	{
		segment->originX = 0;
		segment->originY += segment->height;
	}

	if (segment->originY >= height)
		result = 0;
	else
		result = segment;

	if (result)
	{
		for(unsigned int y=0; y<segment->height; y++)
			for(unsigned int x=0; x<segment->width; x++)
			{
				segment->SetComponent(x, y, GetComponent(segment->originX+x, segment->originY+y));
			}
	}

	return result;
}

void Image::UpdateWithSegment()
{
	if (!segment)
		return;

	for(unsigned int y=0; y<segment->height; y++)
		for(unsigned int x=0; x<segment->width; x++)
		{
			SetComponent(segment->originX+x, segment->originY+y, segment->GetComponent(x, y));
		}
}
